#include <iostream>

namespace bga
{

template< typename T >
Vector3<T>::Vector3()
{
}

template< typename T >
Vector3<T>::Vector3(T x, T y, T z)
{
    this->arrayValues[0] = x;
    this->arrayValues[1] = y;
    this->arrayValues[2] = z;
}

template< typename T >
Vector3<T>::Vector3(const Vector3<T>& vector)
{
    this->arrayValues[0] = vector.getX();
    this->arrayValues[1] = vector.getY();
    this->arrayValues[2] = vector.getZ();
}

template< typename T >
Vector3<T>::~Vector3()
{

}

template< typename T >
T Vector3<T>::getX() const
{
    return this->arrayValues[0];
}

template< typename T >
T Vector3<T>::getY() const
{
    return this->arrayValues[1];
}

template< typename T >
T Vector3<T>::getZ() const
{
    return this->arrayValues[2];
}

template< typename T >
void Vector3<T>::setX(T X)
{
    this->arrayValues[0] = X;
}

template< typename T >
void Vector3<T>::setY(T Y)
{
    this->arrayValues[1] = Y;
}

template< typename T >
void Vector3<T>::setZ(T Z)
{
    this->arrayValues[2] = Z;
}

template< typename T >
void Vector3<T>::setXYZ(T X, T Y, T Z)
{
    this->arrayValues[0] = X;
    this->arrayValues[1] = Y;
    this->arrayValues[2] = Z;
}

template< typename T >
double Vector3<T>::getNorm() const
{
    return sqrt( this->getX() * this->getX() + this->getY() * this->getY() + this->getZ() * this->getZ() );
}

template< typename T >
void Vector3<T>::normalize()
{
    double norm = this->getNorm();
    this->arrayValues[0] /= norm;
    this->arrayValues[1] /= norm;
    this->arrayValues[2] /= norm;
}

template< typename T >
Vector3<T> Vector3<T>::normalize(const Vector3<T>& aNormer)
{
    Vector3<T> vector(aNormer);
    vector.normalize();
    return vector;
}

template< typename T >
Vector3<T> Vector3<T>::crossProduct(const Vector3<T>& v1, const Vector3<T>& v2)
{
    Vector3<T> res;
    res.setXYZ(v1.getY() * v2.getZ() - v1.getZ() * v2.getY(),
                v1.getZ() * v2.getX() - v1.getX() * v2.getZ(),
                v1.getX() * v2.getY() - v1.getY() * v2.getX());
    return res;
}

template< typename T >
void Vector3<T>::crossProduct(const Vector3<T>& V)
{
    this->setXYZ(this->getY() * V.getZ() - this->getZ() * V.getY(),
                this->getZ() * V.getX() - this->getX() * V.getZ(),
                this->getX() * V.getY() - this->getY() * V.getX());
}

template< typename T >
Vector3<T> Vector3<T>::operator+(const Vector3<T> &V) const
{
    return Vector3<T>(this->getX() + V.getX(),
                    this->getY() + V.getY(),
                    this->getZ() + V.getZ());
}

template< typename T >
Vector3<T>& Vector3<T>::operator+=(const Vector3<T> &V)
{
    this->setX(this->getX() + V.getX());
    this->setY(this->getY() + V.getY());
    this->setZ(this->getZ() + V.getZ());
    return *this;
}

template< typename T >
Vector3<T> Vector3<T>::operator-(const Vector3<T> &V) const
{
    return Vector3<T>(this->getX() - V.getX(),
                    this->getY() - V.getY(),
                    this->getZ() - V.getZ());
}

template< typename T >
Vector3<T>& Vector3<T>::operator-=(const Vector3<T> &V)
{
    this->setX(this->getX() - V.getX());
    this->setY(this->getY() - V.getY());
    this->setZ(this->getZ() - V.getZ());
    return *this;
}

template< typename T >
template< typename U >
Vector3<T> Vector3<T>::operator*(U value) const
{
    return Vector3<T>(this->getX() * value,
                    this->getY() * value,
                    this->getZ() * value);
}

template< typename T >
double Vector3<T>::operator*(const Vector3<T>& v) const
{
    return (this->getX() * v.getX() +
                    this->getY() * v.getY() +
                    this->getZ() * v.getZ());
}

template< typename T >
Vector3<T>& Vector3<T>::operator=(const Vector3<T>& v)
{
    this->arrayValues[0] = v.getX();
    this->arrayValues[1] = v.getY();
    this->arrayValues[2] = v.getZ();
    return *this;
}

template< typename T>
std::ostream& operator<< (std::ostream& stream, const Vector3<T>& V)
{
    stream << V.getX() << "   " << V.getY() << "   " << V.getZ() ;
    return stream;
}

}
